﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureInstanceJoinBehavior.h"
#include "IRegeneratorDataIdCreator.h"
#include "IDocument.h"
#include "IRegenerator.h"
#include "IInstance.h"
#include "IJoinRelationshipBehavior.h"
#include "DbObjectUtils.h"
#include "IElementJoin.h"
#include "JoinUtils.h"
#include "ElementJoinUtils.h"
#include "JoinCutInstanceUtils.h"
#include "JoinConditionUtils.h"
#include "IElementPositionPoints.h"
#include "ICurve3d.h"
#include "IBaseGraphicsElementShapeComponent.h"
#include "Vector3dUtils.h"
#include "AlgorithmBodyTopologyOperate.h"
#include "ISurface.h"
#include "IFace.h"
#include "ILine3d.h"
#include "ICurve3dSurfaceIntersection.h"
#include "AlgorithmIntersect.h"
#include "IGraphicsBRepBody.h"
#include "IGraphicsElementShape.h"
#include "GraphicsNodeUtils.h"

#include "GbmpGraphicsNodeUtils.h"
#include "GbmpJoinCutInstanceUtils.h"
#include "GbmpJoinConditionUtils.h"
#include "GbmpJoinUtils.h"
#include "ElementJoinEx.h"
#include "IGeometryRelationshipComponent.h"

#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"
using namespace gcmp;

// 暂时处理JoinUtil废弃警告，后续JoinUtil私有化后把这里恢复

IMPLEMENT_REGEN_FUNCTIONS(gcmp, StructureInstanceJoinBehavior, JoinType)

DBOBJECT_DATA_DEFINE(StructureInstanceJoinBehavior)
{
}

gcmp::StructureInstanceJoinBehavior::StructureInstanceJoinBehavior(IDocument* pDoc, JoinType joinType, bool isChangeJoinTypeAllowed)
    : m_pDoc(pDoc)
    , m_JoinType(joinType)
    , m_IsChangeJoinTypeAllowed(isChangeJoinTypeAllowed)
{
    SetIsChangePriAndSecAllowed(true);
}

StructureInstanceJoinBehavior::~StructureInstanceJoinBehavior()
{
    //     std::wstringstream oss;
    //     oss << L"WallJoin deletion: " << GetAttachingId() << L" " << GetAttachingPosition() << L" " << GetAttachedId() << L" " << GetAttachedPosition() << std::endl;
    //     DUMP_SIMPLIFIED(oss.str());
}

IElementJoin * gcmp::StructureInstanceJoinBehavior::GetElementJoin() const
{
    IElementJoin* pElement = quick_cast<IElementJoin>(m_pDoc->GetElement(m_OwnerElementId));
    return pElement;
}

std::pair<ElementId, JoinPosition> gcmp::StructureInstanceJoinBehavior::GetInstanceJoinPartnerByInstanceIdAndEnd(const IDocument* pDoc, ElementId elementId, JoinPosition joinEnd)
{
    std::pair<ElementId, JoinPosition> noJoinPartner = std::make_pair(ElementId::InvalidID, JoinPosition::Invalid);
    DBG_WARN_AND_RETURN_UNLESS(pDoc, noJoinPartner, L"传入的文档为空",L"GDMPLab",L"2024-03-30");
    std::vector<IElementJoin*> pJoins = ElementJoinUtils::GetElementJoinByJoinPosition(pDoc, elementId, joinEnd);
    if (pJoins.empty())
    {
        return noJoinPartner;
    }
    
    IElementJoin* pJoin = nullptr;
    if (pJoins.at(0))
    {
        pJoin = pJoins.at(0);
    }
    else
    {
        return noJoinPartner;
    }

    if (pJoin->GetAttachingId() == elementId)
        return std::make_pair(pJoin->GetAttachedId(), pJoin->GetAttachedPosition());

    if (pJoin->GetAttachedId() == elementId)
        return std::make_pair(pJoin->GetAttachingId(), pJoin->GetAttachingPosition());

    return noJoinPartner;
}

std::pair<const IInstance*, bool>  StructureInstanceJoinBehavior::GetFaceInstance(const IInstance* pRegenInstance, const IElementJoin* pInstanceJoin) const
{
    std::pair<const IInstance*, bool> res(nullptr, false); //第二个参数若是true，表示第一个参数是Attached对象
    DBG_WARN_AND_RETURN_UNLESS(pInstanceJoin, res, L"无效pInstanceJoin",L"GDMPLab",L"2024-03-30");

    const IInstance* pInstance = pRegenInstance; // const_cast<Instance*>(pRegenInstance);
    DBG_WARN_AND_RETURN_UNLESS(pInstance, res, L"无效pInstance",L"GDMPLab",L"2024-03-30");

    ElementId otherElementId;
    if (pInstanceJoin->GetAttachedId() == pInstance->GetElementId())
    {
        otherElementId = pInstanceJoin->GetAttachingId();
        res.second = false;
    }
    else if (pInstanceJoin->GetAttachingId() == pInstance->GetElementId())
    {
        otherElementId = pInstanceJoin->GetAttachedId();
        res.second = true;
    }
    
    IInstance* pOtherInstance =dynamic_cast<IInstance*>(m_pDoc->GetElement(otherElementId));
    DBG_WARN_AND_RETURN_UNLESS(pOtherInstance, res, L"无效pOtherInstance",L"GDMPLab",L"2024-03-30");
    res.first = pOtherInstance;
    return res;
}

// 获取给定的 joinId 在给定pInstance哪个端点
JoinPosition StructureInstanceJoinBehavior::GetJoinPosition(const IInstance* pInstance, ElementId joinId) const
{
    JoinPosition joinPosition = JoinPosition::Invalid;

    DBG_WARN_AND_RETURN_UNLESS(pInstance && joinId.IsValid(), joinPosition, L"Invalid Argument",L"GDMPLab",L"2024-03-30");

    const IGeometryRelationshipComponent* pGeometryRepCpt = pInstance->GetGeometryRelationshipComponent();
    DBG_WARN_AND_RETURN_UNLESS(pGeometryRepCpt, joinPosition,  L"pGeometryRepCpt为空",L"GDMPLab",L"2024-03-30");

    if (const IJoinRelationshipBehavior* pJoinRelationshipBehavior = pGeometryRepCpt->GetJoinRelationship())
    {
        const std::vector<ElementId>& startJoinIds = pJoinRelationshipBehavior->GetElementJoinIdsAtStart();
        DBG_WARN_AND_RETURN_UNLESS(startJoinIds.size() <= 1, joinPosition, L"默认的连接不支持端点处一对多连接",L"GDMPLab",L"2024-03-30");
        if (std::find(startJoinIds.begin(), startJoinIds.end(), joinId) != startJoinIds.end())
            return JoinPosition::Start;

        const std::vector<ElementId>& endJoinIds = pJoinRelationshipBehavior->GetElementJoinIdsAtEnd();
        DBG_WARN_AND_RETURN_UNLESS(endJoinIds.size() <= 1, joinPosition, L"默认的连接不支持端点处一对多连接",L"GDMPLab",L"2024-03-30");
        if (std::find(endJoinIds.begin(), endJoinIds.end(), joinId) != endJoinIds.end())
            return JoinPosition::End;

        const std::vector<ElementId>& middleJoinIds = pJoinRelationshipBehavior->GetElementJoinIdsAtMiddle();
        if (std::find(middleJoinIds.begin(), middleJoinIds.end(), joinId) != middleJoinIds.end())
            return JoinPosition::Middle;
    }

    return joinPosition;
}

void gcmp::StructureInstanceJoinBehavior::ReportInputDataIds(std::vector<RegenDataId>& regenDataIds) const
{
    regenDataIds.push_back(GetJoinTypeRdId());
}

bool StructureInstanceJoinBehavior::CalculateJoinedGraphicsElementShape(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pTargetElement && pBaseGraphicsElementShape, L"Invalid Argument",L"GDMPLab",L"2024-03-30");

    IDocument *pDoc = GetDocument();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");

    IElementJoin* pElementJoin = quick_cast<IElementJoin>(GetElementJoin());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementJoin, L"无效pInstanceJoin",L"GDMPLab",L"2024-03-30");

    IInstance *pAttachingInstance = dynamic_cast<IInstance*>(pDoc->GetElement(pElementJoin->GetAttachingId()));
    IInstance *pAttachedInstance = dynamic_cast<IInstance*>(pDoc->GetElement(pElementJoin->GetAttachedId()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance && pAttachedInstance, L"无效pAttached/pAttachingInstance",L"GDMPLab",L"2024-03-30");

    // 检查可连接性
    if (!GbmpJoinCutInstanceUtils::IsJoinable(pAttachingInstance) || !GbmpJoinCutInstanceUtils::IsJoinable(pAttachedInstance))
    {
        return false;
    }

    bool res = false;
    JoinType type = GetJoinType();

    ReCalculateJoinAttachedAndAttachingRelation(pElementJoin, type);
    bool isCheck = true;
    if (type == JoinType::TType)
    {
        if ((pElementJoin->GetAttachedId() == pTargetElement->GetElementId() && pElementJoin->GetAttachedPosition() == JoinPosition::Middle)
            || (pElementJoin->GetAttachingId() == pTargetElement->GetElementId() && pElementJoin->GetAttachingPosition() == JoinPosition::Middle))
        {
            isCheck= false;
        }
    }

    if (isCheck && !GbmpJoinConditionUtils::IsSatisfyGeometryJoin(pDoc, pElementJoin))
    {
        bool isReverseRelationship = ElementJoinEx::ReverseRelationship(pElementJoin);
        if (!isReverseRelationship)
        {
            return false;
        }
        if (isReverseRelationship && !GbmpJoinConditionUtils::IsSatisfyGeometryJoin(pDoc, pElementJoin))
        {
            return false;
        }
    }
    
    switch (type)
    {
    case JoinType::Abut:
        res = ExecuteForAbutJion(pTargetElement, pBaseGraphicsElementShape, opJoinedGraphicsElementShape);
        break;
    case JoinType::Miter:
        res = ExecuteForMiterJion(pTargetElement, pBaseGraphicsElementShape, opJoinedGraphicsElementShape);
        break;
    case JoinType::SquareOff:
        res = ExecuteForSquareOffJion(pTargetElement, pBaseGraphicsElementShape, opJoinedGraphicsElementShape);
        break;
    case JoinType::TType:
        res = ExecuteForTTypeJion(pTargetElement, pBaseGraphicsElementShape, opJoinedGraphicsElementShape);
        break;
    default:
        break;
    }

    return res;
}

bool gcmp::StructureInstanceJoinBehavior::IsCutterGraphicsElementShapeJoinable() const
{
    return false;
}

bool StructureInstanceJoinBehavior::ExecuteForAbutJion(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape)
{
    IInstance* pInstance = quick_cast<IInstance>(pTargetElement);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pInstance, L"目标Element不见了",L"GDMPLab",L"2024-03-30");

    IElementJoin* pElementJoin = quick_cast<IElementJoin>(GetElementJoin());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementJoin, L"无效pInstanceJoin",L"GDMPLab",L"2024-03-30");
  
   //第二个参数若是true，表示第一个参数是Attached对象
    std::pair<const IInstance*, bool> standInstance = GetFaceInstance(pInstance, pElementJoin);
    const IInstance* pStandInstance = standInstance.first;
    if (pStandInstance == nullptr)
    {
        return false;
    }

    Vector3d ptJoin = Vector3d::Zero;    
    if (!CanJoinAtEndPoint(pInstance, pStandInstance, ptJoin))
    {
        return false;
    }
    
    OwnerPtr<IGraphicsElementShape> upGRep = GetJoinedGraphicsElementShape(pInstance, pBaseGraphicsElementShape, pStandInstance, ptJoin, JoinType::Abut, standInstance.second);

    opJoinedGraphicsElementShape = TransferOwnership(upGRep);

    return opJoinedGraphicsElementShape.get() != nullptr;
}

bool StructureInstanceJoinBehavior::ExecuteForMiterJion(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape)
{
    return false;
}

bool StructureInstanceJoinBehavior::ExecuteForSquareOffJion(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape)
{
    IInstance* pInstance = quick_cast<IInstance>(pTargetElement);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pInstance, L"目标Element不见了",L"GDMPLab",L"2024-03-30");

    IElementJoin* pElementJoin = quick_cast<IElementJoin>(GetElementJoin());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementJoin, L"无效pInstanceJoin",L"GDMPLab",L"2024-03-30");
    //第二个参数若是true，表示第一个参数是Attached对象
    std::pair<const IInstance*, bool> standInstance = GetFaceInstance(pInstance, pElementJoin);
    const IInstance* pStandInstance = standInstance.first;
    if (pStandInstance == nullptr)
    {
        return false;
    }

    Vector3d ptJoin = Vector3d::Zero;
    if (!CanJoinAtEndPoint(pInstance, pStandInstance, ptJoin))
    {
        return false;
    }

    OwnerPtr<IGraphicsElementShape> upGRep = GetJoinedGraphicsElementShape(pInstance, pBaseGraphicsElementShape, pStandInstance, ptJoin, JoinType::SquareOff, standInstance.second);

    opJoinedGraphicsElementShape = TransferOwnership(upGRep);

    return opJoinedGraphicsElementShape.get() != nullptr;
}

bool gcmp::StructureInstanceJoinBehavior::ExecuteForTTypeJion(IElement* pTargetElement, const IGraphicsElementShape* pBaseGraphicsElementShape, OwnerPtr<IGraphicsElementShape>& opJoinedGraphicsElementShape)
{
    IInstance* pInstance = quick_cast<IInstance>(pTargetElement);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pInstance, L"目标Element不见了",L"GDMPLab",L"2024-03-30");
    
    IElementJoin* pInstanceJoin = quick_cast<IElementJoin>(GetElementJoin());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pInstanceJoin, L"无效pInstanceJoin",L"GDMPLab",L"2024-03-30");

    // 得到当前 pInstanceJoin 在 pInstance 的哪个端点
    JoinPosition instJoinPosition = GetJoinPosition(pInstance, pInstanceJoin->GetElementId());
    if (instJoinPosition == JoinPosition::Invalid || instJoinPosition == JoinPosition::Middle) //中间连接、被attached的instance不处理
        return true;

    std::pair<const IInstance*, bool> standInstance = GetFaceInstance(pInstance, pInstanceJoin);
    const IInstance* pStandInstance = standInstance.first;
    if (pStandInstance == nullptr)
    {
        return false;
    }

    OwnerPtr<ICurve3d> opStandCurve = JoinCutInstanceUtils::GetPositionCurve(pStandInstance);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opStandCurve, L"无效opStandCurve",L"GDMPLab",L"2024-03-30");

    const IElementPositionPoints* pCtrlPtBehavior = pInstance->GetPositionPoints();
    Vector3d ptJoinOnInstance = pCtrlPtBehavior ? pCtrlPtBehavior->GetControlPoint((int32_t)instJoinPosition) : Vector3d::Zero;
    Vector3d ptJoin = ptJoinOnInstance;
    ptJoin.SetZ(opStandCurve->GetStartPoint().GetZ());
    double pointParam = 0;
    bool bIsParamInRange = false;
    if (!opStandCurve->GetParameter(ptJoin, pointParam, bIsParamInRange, Constants::LENGTH_EPS))
    {
        return false;
    }

    if (!bIsParamInRange)
    {
        return false;
    }

    OwnerPtr<IGraphicsBRepBody> opGBody = GbmpGraphicsNodeUtils::GetGRepBody(GetDocument(), pBaseGraphicsElementShape);
    IFace* pTractiveFaceOnExtendedBody = JoinConditionUtils::GetTractiveFace(pInstance, opGBody.get(), ptJoin);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pTractiveFaceOnExtendedBody, L"无效pTractiveFaceOnExtendedBody",L"GDMPLab",L"2024-03-30");
    
    const IBaseGraphicsElementShapeComponent* pBaseGraphicsElementShapeComponent = pStandInstance->GetBaseGraphicsElementShapeComponent();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pBaseGraphicsElementShapeComponent, L"pBaseGraphicsElementShapeComponent为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IGraphicsBRepBody> opStandBody = GbmpGraphicsNodeUtils::GetGRepBody(GetDocument(), pBaseGraphicsElementShapeComponent->GetBaseGraphicsElementShape());
    std::vector<int> standInstaceInteriorAndExteriorFaceIds = JoinConditionUtils::GetInteriorAndExteriorFaceIds(pStandInstance);

    OwnerPtr<ISurface> pTargetedFace = nullptr;
    if (pInstanceJoin->GetAttachingId() == pInstance->GetElementId() &&
        pInstanceJoin->GetAttachedPosition() == JoinPosition::Middle)
    {
        if (!GbmpJoinConditionUtils::AreInstancesHaveVerticalOverlap(pInstance, pStandInstance))
        {
            return false;
        }

        //不在中间区域点时
        if (Vector3dUtils::IsEqual(opStandCurve->GetStartPoint(), ptJoin) ||
            Vector3dUtils::IsEqual(opStandCurve->GetEndPoint(), ptJoin))
        {
            return false;
        }
      
        //1、T形连接
        IFace* pTractiveFaceOnStandBody = JoinConditionUtils::GetTractiveFace(pStandInstance, opStandBody.get(), ptJoin);
        DBG_WARN_AND_RETURN_FALSE_UNLESS(pTractiveFaceOnStandBody, L"无效pTractiveFaceOnStandBody",L"GDMPLab",L"2024-03-30");
        pTargetedFace = JoinConditionUtils::GetTargetedFaceByTType(pInstance, opStandBody.get(), pTractiveFaceOnStandBody, standInstaceInteriorAndExteriorFaceIds, ptJoin);
    }
    if (pTargetedFace == nullptr) //拖拽时，由于先调用Regenerate()，会先触发计算器。此时连接点还没有被删除。
    {
        return false;
    }

    // 牵引面附着到目标面
    if (!AlgorithmBodyTopologyOperate::FitBodyToTargetedFaceWithoutTopoChange(pTargetedFace.get(), opGBody->GetGeometryFW(), pTractiveFaceOnExtendedBody, !standInstance.second))
    {
        return false;
    }
    // 连接之前的 GRep
    OwnerPtr<IGraphicsElementShape> upGRep = TransferOwnershipCast<IGraphicsElementShape>(pBaseGraphicsElementShape->Clone());

    // 用连接后的body替换原来的body。
    std::vector<const IGraphicsBRepBody*> bodies;
    std::vector<Matrix4d> transforms;
    std::vector<std::vector<const IGraphicsNode*>> paths;
    GraphicsNodeUtils::CollectBRepBodies(GetDocument(), upGRep.get(), &bodies, &transforms, &paths);
    //找出实体Body，默认墙只有一个实体，排除Shell Body，比如墙的中心面，族中作为项目参照的参照平面等
    int bodyIndex = -1;
    FOR_EACH_INDEX(gbodyIndex, bodies)
    {
        if (!bodies[gbodyIndex]->IsShell())
        {
            bodyIndex = gbodyIndex;
            break;
        }
    }
    GraphicsNodeUtils::ReplaceBRepBody(GetDocument(), upGRep.get(), bodyIndex, TransferOwnership(opGBody));
    opJoinedGraphicsElementShape = TransferOwnership(upGRep);
    return opJoinedGraphicsElementShape.get() != nullptr;
}

bool StructureInstanceJoinBehavior::SetJoinType(JoinType value)
{
    SetJoinType__(value);
    return true;
}

JoinType StructureInstanceJoinBehavior::GetJoinType()
{
    JoinType type = GetJoinType__();
    if (IsChangeJoinTypeAllowed())
    {
        JoinType typeRes = JoinType::InvalidJoinType;
        IElementJoin* pElementJoin = quick_cast<IElementJoin>(GetElementJoin());
        if (pElementJoin == nullptr) //连接为建立时，直接返回存的连接类型； 类型建立后，根据角度自动切换
        {
            return type;
        }
        IInstance *pAttachingInstance = dynamic_cast<IInstance*>(m_pDoc->GetElement(pElementJoin->GetAttachingId())); 
        IInstance *pAttachedInstance = dynamic_cast<IInstance*>(m_pDoc->GetElement(pElementJoin->GetAttachedId()));
        DBG_WARN_AND_RETURN_UNLESS(pAttachingInstance && pAttachedInstance, typeRes, L"无效pAttached/pAttachingInstance",L"GDMPLab",L"2024-03-30");

        JoinPosition attachingPos = GetJoinPosition(pAttachingInstance, pElementJoin->GetElementId());
        JoinPosition instJoinPosition = GetJoinPosition(pAttachedInstance, pElementJoin->GetElementId());
        if ((attachingPos != JoinPosition::Invalid && attachingPos != JoinPosition::Middle
            && instJoinPosition != JoinPosition::Invalid && instJoinPosition != JoinPosition::Middle))
        {
            if (JoinUtils::GetDefaultLJoinType(pAttachingInstance, attachingPos, pAttachedInstance, instJoinPosition, typeRes))
            {
                SetJoinType(typeRes);
                return typeRes;
            }
            return JoinType::InvalidJoinType;
        }
    }
    return type;
}
bool gcmp::StructureInstanceJoinBehavior::CanJoinAtEndPoint(const IInstance* pTargetInstance, const IInstance* pStandInstance, Vector3d& ptJoin)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pTargetInstance, L"无效pTargetInstance",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pStandInstance, L"无效pStandInstance",L"GDMPLab",L"2024-03-30");
    IElementJoin* pElementJoin = quick_cast<IElementJoin>(GetElementJoin());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementJoin, L"无效pInstanceJoin",L"GDMPLab",L"2024-03-30");

    // 得到当前 pInstanceJoin 在 pInstance 的哪个端点
    JoinPosition instJoinPosition = GetJoinPosition(pTargetInstance, pElementJoin->GetElementId());
    if (instJoinPosition == JoinPosition::Invalid || instJoinPosition == JoinPosition::Middle) //中间连接、被attached的instance不处理
    {
        DBG_WARN(L"连接位置不正确",L"GDMPLab",L"2024-03-30");
        return false;
    }
    IInstance *pAttachingInstance = dynamic_cast<IInstance*>(m_pDoc->GetElement(pElementJoin->GetAttachingId()));
    IInstance *pAttachedInstance = dynamic_cast<IInstance*>(m_pDoc->GetElement(pElementJoin->GetAttachedId()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pAttachingInstance && pAttachedInstance, L"无效pAttached/pAttachingInstance",L"GDMPLab",L"2024-03-30");

    Vector3d ptJoinOnAttached = ElementJoinEx::GetJoinPointOnAttached(pElementJoin);
    Vector3d ptJoinOnAttaching = ElementJoinEx::GetJoinPointOnAttaching(pElementJoin);
    if (!GbmpJoinConditionUtils::AreInstancePointAlmostEqual(pAttachingInstance, ptJoinOnAttaching, pAttachedInstance, ptJoinOnAttached))
    {
        return false;
    }

    OwnerPtr<ICurve3d> opStandCurve = JoinCutInstanceUtils::GetPositionCurve(pStandInstance);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(opStandCurve, L"无效opStandCurve",L"GDMPLab",L"2024-03-30");

    const IElementPositionPoints* pCtrlPtBehavior = pTargetInstance->GetPositionPoints();
    Vector3d ptJoinOnInstance = pCtrlPtBehavior ? pCtrlPtBehavior->GetControlPoint((int32_t)instJoinPosition) : Vector3d::Zero;
    ptJoin = ptJoinOnInstance;
    ptJoin.SetZ(opStandCurve->GetStartPoint().GetZ());
    double pointParam = 0;
    bool bIsParamInRange = false;
    if (!opStandCurve->GetParameter(ptJoin, pointParam, bIsParamInRange, Constants::LENGTH_EPS))
    {
        return false;
    }

    if (!bIsParamInRange)
    {
        return false;
    }
    return true;
}

gcmp::OwnerPtr<gcmp::IGraphicsElementShape> gcmp::StructureInstanceJoinBehavior::GetJoinedGraphicsElementShape(const IInstance* pTargetInstance, const IGraphicsElementShape* pBaseGraphicsElementShape, const IInstance* pStandInstance, Vector3d& ptJoin, JoinType type, bool bIsExtendedFirst)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pTargetInstance, L"目标Element不见了",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pBaseGraphicsElementShape, L"pBaseGraphicsElementShape为空",L"GDMPLab",L"2024-03-30");
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pStandInstance, L"pStandInstance为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<gcmp::ISurface> pTargetedFace = nullptr;
    if (type == JoinType::Abut)
    {
        pTargetedFace = JoinConditionUtils::GetTargetedFaceByAbutJion(pTargetInstance, pStandInstance, ptJoin, bIsExtendedFirst);
    }
    else if (type == JoinType::SquareOff)
    {
      pTargetedFace = JoinConditionUtils::GetTargetedFaceBySquareJoin(pTargetInstance, pStandInstance, ptJoin, bIsExtendedFirst);
    }
    if (!pTargetedFace)
    {
        return nullptr;
    }
    OwnerPtr<IGraphicsBRepBody> opGBody = GbmpGraphicsNodeUtils::GetGRepBody(GetDocument(), pBaseGraphicsElementShape);

    IFace* pTractiveFaceOnExtendedBody = JoinConditionUtils::GetTractiveFace(pTargetInstance, opGBody.get(), ptJoin);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pTractiveFaceOnExtendedBody, L"无效pTractiveFaceOnExtendedBody",L"GDMPLab",L"2024-03-30");

//#ifdef _DEBUG
    const IBaseGraphicsElementShapeComponent* pBaseGraphicsElementShapeComponent = pStandInstance->GetBaseGraphicsElementShapeComponent();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pBaseGraphicsElementShapeComponent, L"pBaseGraphicsElementShapeComponent为空",L"GDMPLab",L"2024-03-30");
    OwnerPtr<IGraphicsBRepBody> opStandBody = GbmpGraphicsNodeUtils::GetGRepBody(GetDocument(), pBaseGraphicsElementShapeComponent->GetBaseGraphicsElementShape());
    std::wstring strStandBody = opStandBody->GetStringForDebug();
    std::wstring strTargetedFace = pTargetedFace->GetStringForDebug();
    std::wstring strPreBody = opGBody->GetStringForDebug();
    std::wstring strTractiveFace = pTractiveFaceOnExtendedBody->GetStringForDebug();
//#endif // DEBUG
  
    if (type == JoinType::SquareOff)
    {
        OwnerPtr<ICurve3d> opCurve = nullptr;
        if (!bIsExtendedFirst)//pTargetInstance他为主时，如果连接点及定位线的中点的连线与目标面有交点时，表示其也需要被裁剪
        {
            OwnerPtr<ICurve3d> pCurve = JoinCutInstanceUtils::GetPositionCurve(pTargetInstance);
            opCurve = ILine3d::Create(ptJoin, pCurve->GetMiddlePoint());
            std::vector<OwnerPtr<ICurve3dSurfaceIntersection>> opIntersects;
            bool interset = AlgorithmIntersect::Intersect(opCurve.get(), pTargetedFace.get(), opIntersects);
            if (opIntersects.size() > 0)
            {
                bIsExtendedFirst = !bIsExtendedFirst;
            }
        }        
    }
    // 牵引面附着到目标面
    if (!AlgorithmBodyTopologyOperate::FitBodyToTargetedFaceWithoutTopoChange(pTargetedFace.get(), opGBody->GetGeometryFW(), pTractiveFaceOnExtendedBody, !bIsExtendedFirst))
    {
        return nullptr;
    }
    // 连接之前的 GRep
    OwnerPtr<IGraphicsElementShape> upGRep = TransferOwnershipCast<IGraphicsElementShape>(pBaseGraphicsElementShape->Clone());

#ifdef _DEBUG
    std::wstring strBody = opGBody->GetStringForDebug();
#endif // DEBUG

    // 用连接后的body替换原来的body。
    std::vector<const IGraphicsBRepBody*> bodies;
    std::vector<Matrix4d> transforms;
    std::vector<std::vector<const IGraphicsNode*>> paths;
    GraphicsNodeUtils::CollectBRepBodies(GetDocument(), upGRep.get(), &bodies, &transforms, &paths);
    //找出实体Body，默认墙只有一个实体，排除Shell Body，比如墙的中心面，族中作为项目参照的参照平面等
    int bodyIndex = -1;
    FOR_EACH_INDEX(gbodyIndex, bodies)
    {
        if (!bodies[gbodyIndex]->IsShell())
        {
            bodyIndex = gbodyIndex;
            break;
        }
    }
    GraphicsNodeUtils::ReplaceBRepBody(GetDocument(), upGRep.get(), bodyIndex, TransferOwnership(opGBody));
    return upGRep;
}

void gcmp::StructureInstanceJoinBehavior::ReCalculateJoinAttachedAndAttachingRelation(IElementJoin* pElementJoin, JoinType type)
{
    if (type == JoinType::InvalidJoinType)
    {
        return;
    }
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementJoin, L"无效pInstanceJoin",L"GDMPLab",L"2024-03-30");
    IDocument *pDoc = GetDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"无效pDoc",L"GDMPLab",L"2024-03-30");
    IInstance *pAttachingInstance = dynamic_cast<IInstance*>(pDoc->GetElement(pElementJoin->GetAttachingId()));
    IInstance *pAttachedInstance = dynamic_cast<IInstance*>(pDoc->GetElement(pElementJoin->GetAttachedId()));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pAttachingInstance && pAttachedInstance, L"无效pAttached/pAttachingInstance",L"GDMPLab",L"2024-03-30");

    //判断主次
    JoinData joinData(pElementJoin->GetAttachingId(), pElementJoin->GetAttachingPosition(), pElementJoin->GetAttachedId(), pElementJoin->GetAttachedPosition());

    if (GbmpJoinUtils::GetJoinData(pAttachingInstance, pElementJoin->GetAttachingPosition(), pAttachedInstance, pElementJoin->GetAttachedPosition(), type, joinData)) //判断优先级
    {
        if (joinData.AttachedElementId != pElementJoin->GetAttachedId())//主次不同时，pElementJoin反转
        {
            ElementJoinEx::ReverseRelationship(pElementJoin);
        }
    }
}

